#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstring>
#include "log.hpp"
#include <functional>
#include "callbackFun.hpp"
#define BUFFERSIZE 1024

Log lg(SCREEN);
cbFun *cb_fun2 = new cbFun();

using cb_fun = std::function<std::string(const std::string &)>; // 类型重命名
static std::string defaultIp = "0.0.0.0";

std::string romote_contral(const std::string &_command)
{
    // popen的功能:管道+子进程执行命令的接口，底层fork子进程执行命令，
    //  再利用管道返回给调用方

    FILE *fp = popen(_command.c_str(), "r");
    if (nullptr == fp)
    {
        perror("popen");
        return "error";
    }
    std::string result;
    char buffer[4096];
    while (true)
    {
        // fgets的作用就是从流中读取n个字符到buffer中
        char *ok = fgets(buffer, sizeof(buffer), fp);
        if (ok == nullptr)
            break;
        result += buffer;
        // 这样写的目的是避免内容比buffer大
    }
    pclose(fp);

    return result;
}

class udpServer
{
public:
    udpServer(uint16_t _port, std::string _ip = defaultIp) // 缺省只能从后往前
        : ip_(_ip), port_(_port), sock_fd_(0)
    {
    }

    // 初始化
    void init()
    {
        // 制作文件描述符
        sock_fd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sock_fd_ == -1)
        {
            lg(FATAL, "socket create error,sockfd:%d", sock_fd_);
            exit(1);
        }
        lg(INFO, "sockfd create success,sockfd:%d", sock_fd_);

        // 绑定ip和端口
        struct sockaddr_in local;                       // 该结构体在apra/inet中
        bzero(&local, sizeof(local));                   // 将该内存块全部填充成0
        local.sin_family = AF_INET;                     // ipv4
        local.sin_port = htons(port_);                  // 端口转网络字节序（大端）
        local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 字符串转网络字节序ip
        // local.sin_addr.s_addr = inet_addr(INADDR_ANY);//INADDR_ANY = 0.0.0.0

        if (bind(sock_fd_, reinterpret_cast<struct sockaddr *>(&local), sizeof(local)))
        {
            lg(FATAL, "bind error:%d,err info:%s", errno, strerror(errno));
            exit(1);
        }
        lg(INFO, "bind success:%d,info:%s", errno, strerror(errno));
    }

    // 运行:接受客户端给发的信息，_cbfun用于处理客户端发给我数据
    void run(cb_fun _cbfun = romote_contral)
    {
        isrunning_ = true;
        char inbuffer[BUFFERSIZE];
        while (isrunning_)
        {
            struct sockaddr_in client;
            socklen_t c_sock_len = sizeof(client);
            size_t n = recvfrom(sock_fd_, inbuffer, sizeof(inbuffer), 0, (struct sockaddr *)&client, &c_sock_len);
            if (n < 0)
            {
                lg(FATAL, "recv error:%d,info:%s", errno, strerror(errno));
                continue;
            }
            lg(INFO, "recv success:%d,info:%s", errno, strerror(errno));

            inbuffer[n] = 0;

            /* 远程输入bash*/
            // std::string commond = inbuffer;
            // std::string ret = _cbfun(commond);
            // sendto(sock_fd_, ret.c_str(), ret.size(), 0, (struct sockaddr*)&client,c_sock_len );

            std::string message = inbuffer;
            // 聊天室
            (*cb_fun2)(sock_fd_, client, message);

            
        }
    }

    ~udpServer()
    {
        if (sock_fd_) // 构造的时候为0,只有走了init才有close的意义
            close(sock_fd_);
        delete cb_fun2;
    }

private:
    int sock_fd_;    // 网络文件描述符
    std::string ip_; // 本机ip
    uint16_t port_;  // 本机端口
    bool isrunning_; // 运行状态
};